﻿using Microsoft.EntityFrameworkCore;
using WAU.DAL;
using WAU.DTOs.UserDailyActivityModule;
using WAU.Models;
using WAU.Models.Framework;
using WAU.Models.UserDailyActivityModels;

namespace WAU.Services
{
    /// <summary>
    /// 用户日常活动 Service
    /// </summary>
    public class UserDailyActivityService
    {
        /// <summary>
        /// DailySignRepo
        /// </summary>
        private readonly BaseRepoMysql<UserDailySign> _dailySignRepo;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="dailySignRepo"></param>
        public UserDailyActivityService(BaseRepoMysql<UserDailySign> dailySignRepo)
        {
            this._dailySignRepo = dailySignRepo;
        }

        /// <summary>
        /// 用户日常签到
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult<int>> DailySign(string currentUserId, DailySignDto dto)
        {
            // TODO 便于测试，测试完成后需要移除
            //if (dto.SignInDate != DateOnly.FromDateTime(DateTime.Now))
            //{
            //    return ExecResult<int>.Error("只能签到当前日期");
            //}

            int continueDays = -1;
            string month = dto.SignInDate.ToString("yyyy-MM");
            UserDailySign entity = await _dailySignRepo.FindAsync(a => a.UserId == currentUserId && a.Month == month);

            // 1 判断当前用户给定的月份有没有签到
            // 1.1 如果当月没有签到，则创建一条记录
            if(entity == null)
            {
                UserDailySign userDailySign = new UserDailySign();
                userDailySign.Id = GuidFactory.NewSortedGuid();
                userDailySign.UserId = currentUserId;
                userDailySign.Month = month;

                userDailySign.Creator = currentUserId;
                userDailySign.CreateTime = DateTime.Now;

                byte[] bytePattern = new byte[31];
                bytePattern[dto.SignInDate.Day - 1] = 1;
                userDailySign.SignPattern = bytePattern;
                
                // 查找最近的某个月的签到记录
                UserDailySign recentMonthSignEntity = await _dailySignRepo.QueryNoTracking(a => a.UserId == currentUserId).OrderByDescending(a => a.Month).FirstOrDefaultAsync();

                // 1.1.1 如果存在最近的记录
                if (recentMonthSignEntity != null 
                    && recentMonthSignEntity.ContinuousSignStart != null
                    && recentMonthSignEntity.ContinuousSignEnd != null)
                {
                    // 1.1.1.1 签到连续
                    if(dto.SignInDate == recentMonthSignEntity.ContinuousSignEnd.Value.AddDays(1))
                    {
                        userDailySign.ContinuousSignStart = recentMonthSignEntity.ContinuousSignStart;
                        userDailySign.ContinuousSignEnd = dto.SignInDate;

                        continueDays = userDailySign.ContinuousSignEnd.Value.DayNumber -
                                    userDailySign.ContinuousSignStart.Value.DayNumber + 1;
                    }
                    // 1.1.1.1.2 签到不连续
                    else
                    {
                        userDailySign.ContinuousSignStart = dto.SignInDate;
                        userDailySign.ContinuousSignEnd = dto.SignInDate;

                        continueDays = 1;
                    }
                }
                // 1.1.2 如果不存在最近的记录
                else
                {
                    userDailySign.ContinuousSignStart = dto.SignInDate;
                    userDailySign.ContinuousSignEnd = dto.SignInDate;

                    continueDays = 1;
                }

                _dailySignRepo.Add(userDailySign);
            }
            // 1.2 当月签到了
            else
            {
                if (entity.SignPattern[dto.SignInDate.Day - 1] != 0)
                {
                    return ExecResult<int>.Error("给定的日期已经签到");
                }

                entity.SignPattern[dto.SignInDate.Day - 1] = 1;

                // 1.2.1 签到连续
                if (dto.SignInDate == entity.ContinuousSignEnd.Value.AddDays(1))
                {
                    entity.ContinuousSignEnd = dto.SignInDate;

                    continueDays = entity.ContinuousSignEnd.Value.DayNumber -
                                    entity.ContinuousSignStart.Value.DayNumber + 1;
                }
                // 1.2.2 签到不连续
                else
                {
                    entity.ContinuousSignStart = dto.SignInDate;
                    entity.ContinuousSignEnd = dto.SignInDate;

                    continueDays = 1;
                }
                
                entity.Modifier = currentUserId;
                entity.ModifyTime = DateTime.Now;

                _dailySignRepo.Update(entity);
            }

            await _dailySignRepo.SaveChangesAsync();

            return ExecResult<int>.RetSuccess(continueDays) ;
        }

        /// <summary>
        /// 用户补签
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult<int>> SupplyDailySign(string currentUserId, DailySignDto dto)
        {
            int continueDays = -1;

            // 1. 限制条件判断
            DateOnly nowDate = DateOnly.FromDateTime(DateTime.Now);
            string currentMonth = nowDate.ToString("yyyy-MM");
            string dtoMonth = dto.SignInDate.ToString("yyyy-MM");

            if(currentMonth != dtoMonth)
            {
                return ExecResult<int>.Error("只能补签当月");
            }

            UserDailySign currentMonthEntity = await _dailySignRepo.FindAsync(a => a.UserId == currentUserId && a.Month == currentMonth);
            if(currentMonthEntity == null)
            {
                return ExecResult<int>.Error("用户当月还未签到，不能补签");
            }

            int currentDay = nowDate.Day;
            int toSupplySignDay = dto.SignInDate.Day;

            if (toSupplySignDay > currentDay)
            {
                return ExecResult<int>.Error("不能补签未来的日期");
            }

            if (currentMonthEntity.SignPattern[toSupplySignDay - 1] == 1) 
            {
                return ExecResult<int>.Error("给定日期已经签到，无需补签");
            }

            // 2. 修改数据库中的签到数据
            currentMonthEntity.SignPattern[toSupplySignDay - 1] = 1;

            // 3. 判断当月是否全部连续签到了（当月连续签到次数是否等于当前天数）
            string patternNumberString = string.Join("", currentMonthEntity.SignPattern.Take(currentDay).ToArray()); 
            List<string> splitedByZeroList = patternNumberString.Split('0').Where(a => !string.IsNullOrEmpty(a)).ToList();

            // 3.1 存在多组连续，或当月第一天没有签到（无法与上月连续），则只取最近的一组即可
            if (splitedByZeroList.Count > 1 || !patternNumberString.StartsWith("1"))
            {
                int lastSignIndex = patternNumberString.LastIndexOf("1");
                int lastPartCount = splitedByZeroList.Last().Length;

                currentMonthEntity.ContinuousSignEnd = nowDate.AddDays(1 - nowDate.Day + lastSignIndex);
                currentMonthEntity.ContinuousSignStart = currentMonthEntity.ContinuousSignEnd.Value.AddDays(1 - lastPartCount);
                continueDays = lastPartCount;
            }
            // 3.2 当月全部连续签到了，再查看上个月
            else
            {
                int partCount = splitedByZeroList[0].Length;
                currentMonthEntity.ContinuousSignEnd = nowDate.AddDays(-currentDay + partCount);

                DateOnly lastMonthDate = nowDate.AddMonths(-1);
                string lastMonth = lastMonthDate.ToString("yyyy-MM");
                UserDailySign lastMonthEntity = await _dailySignRepo.FindAsyncNoTracking(a => a.UserId == currentUserId && a.Month == lastMonth);

                DateOnly lastDayOfLastMonth = nowDate.AddDays(-nowDate.Day);
                // 3.2.1 上个月没有记录，或者上个月没有连续签到，则还是统计当前月的
                if (lastMonthEntity == null || 
                    lastMonthEntity.ContinuousSignStart == null || 
                    lastMonthEntity.ContinuousSignEnd == null ||
                    lastMonthEntity.ContinuousSignEnd != lastDayOfLastMonth) 
                {
                    currentMonthEntity.ContinuousSignStart = nowDate.AddDays(1 - currentDay);

                    continueDays = partCount;
                }
                // 3.2.2 上个月有记录，并且上个月有连续签到，则合并记录
                else
                {
                    currentMonthEntity.ContinuousSignStart = lastMonthEntity.ContinuousSignStart;

                    continueDays = currentMonthEntity.ContinuousSignEnd.Value.DayNumber
                                        - currentMonthEntity.ContinuousSignStart.Value.DayNumber + 1;
                }
            }

            currentMonthEntity.Modifier = currentUserId;

            _dailySignRepo.Update(currentMonthEntity);
            await _dailySignRepo.SaveChangesAsync();

            return ExecResult<int>.RetSuccess(continueDays);
        }
    }
}
